package com.haixinga.commbiz.commons.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 18位公民身份证号码是特征组合，由17位数字本体码和1位数字校验码组成。
 * 排列顺序从左至右以此为：6位数字地址码、8位数字出生日期码、3位数字顺序码和1位数字校验码。
 * 地址码：表示编码对象常住户口所在县（市、旗、区）的行政区划代码，按GB/T 2260的规定执行。
 * 出生日期码：表示编码对象出生的年、月、日，GB/T 7408的规定执行。年、月、日代码之间不用分割符。
 * 顺序码：表示在同一地址码所标识的区域范围内，对同年、同月、同日出生的人编定的顺序号。
 * 顺序号的奇数分配给男性，偶数分配给女性。
 * 校验码：校验码采用ISO 7064:1983.MOD 11-2校验码系统。
 * 求校验码方法：对前17位数字本体码加权求和，公式为：S=Sum(Ai*Wi),i=0,1,...,16,
 * 其中Ai表示第i位置上的身份证号号码数字值，Wi表示第i位置上的加权因子，
 * 加权因子的值从0到16位分别为7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2
 * 对S取摸，公式为：Y=mod(S,11)。
 * 通过摸Y得到对应的校验码，对应关系为<0,1>、<1,0>、<2,X>、<3,9>、<4、8>、<5、7>、<6、6>、<7，5>、<8,4>、<9,3>、<10,2>
 * 关系中前者为Y的值，后者为对应的校验码。
 **/

public class IDCardUtil {
    /**
     * 加权因子
     */
    private static final int[] weight = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1};

    /**
     * 校验码
     */
    private static final int[] checkDigit = new int[]{1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2};

    /**
     * 15位身份证号
     */
    private static final Integer FIFTEEN_ID_CARD = 15;

    /**
     * 18位身份证号
     */
    private static final Integer EIGHTEEN_ID_CARD = 18;

    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    private static String getCheckDigit(String eighteenCardId) {
        int remaining = 0;
        if (eighteenCardId.length() == 18) {
            eighteenCardId = eighteenCardId.substring(0, 17);
        }

        if (eighteenCardId.length() == 17) {
            int sum = 0;
            int[] a = new int[17];
            for (int i = 0; i < 17; i++) {
                String k = eighteenCardId.substring(i, i + 1);
                a[i] = Integer.parseInt(k);
            }
            for (int i = 0; i < 17; i++) {
                sum = sum + weight[i] * a[i];
            }

            remaining = sum % 11;
        }

        return remaining == 2 ? "X" : String.valueOf(checkDigit[remaining]);
    }

    private static String update2eighteen(String fifteenCardId) {
        String eighteenCardId = fifteenCardId.substring(0, 6);
        eighteenCardId = eighteenCardId + "19";
        eighteenCardId = eighteenCardId + fifteenCardId.substring(6, 15);
        eighteenCardId = eighteenCardId + getCheckDigit(eighteenCardId);
        return eighteenCardId;
    }

    /**
     * 校验
     *
     * @param idcard idCard
     * @return true/false
     */
    public static Boolean verify(String idcard) {
        if (idcard.length() == FIFTEEN_ID_CARD) {
            idcard = update2eighteen(idcard);
        }
        if (idcard.length() != EIGHTEEN_ID_CARD) {
            return false;
        }

        String checkDigit = idcard.substring(17, 18);
        if (checkDigit.equals(getCheckDigit(idcard))) {
            return true;
        }

        return false;
    }

    /**
     * 根据身份证号获取性别
     *
     * @param IDCard
     * @return
     */
    public static int getSex(String IDCard) {
        int sex = 0;
        if (StringUtils.isNotBlank(IDCard)) {
            //15位身份证号
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                if (Integer.parseInt(IDCard.substring(14, 15)) % 2 == 0) {
                    sex = 2;//"女";
                } else {
                    sex = 1;//"男";
                }
                //18位身份证号
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                // 判断性别
                if (Integer.parseInt(IDCard.substring(16).substring(0, 1)) % 2 == 0) {
                    sex = 2;//"女";
                } else {
                    sex = 1;//"男";
                }
            }
        }
        return sex;
    }

    /**
     * 根据身份证号获取年龄
     *
     * @param IDCard
     * @return
     */
    public static Integer getAge(String IDCard) {
        Integer age = 0;
        Date date = new Date();
        if (StringUtils.isNotBlank(IDCard) && verify(IDCard)) {
            //15位身份证号
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                // 身份证上的年份(15位身份证为1980年前的)
                String uyear = "19" + IDCard.substring(6, 8);
                // 身份证上的月份
                String uyue = IDCard.substring(8, 10);
                // 当前年份
                String fyear = format.format(date).substring(0, 4);
                // 当前月份
                String fyue = format.format(date).substring(5, 7);
                if (Integer.parseInt(uyue) <= Integer.parseInt(fyue)) {
                    age = Integer.parseInt(fyear) - Integer.parseInt(uyear) + 1;
                    // 当前用户还没过生
                } else {
                    age = Integer.parseInt(fyear) - Integer.parseInt(uyear);
                }
                //18位身份证号
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                // 身份证上的年份
                String year = IDCard.substring(6).substring(0, 4);
                // 身份证上的月份
                String yue = IDCard.substring(10).substring(0, 2);
                // 当前年份
                String fyear = format.format(date).substring(0, 4);
                // 当前月份
                String fyue = format.format(date).substring(5, 7);
                // 当前月份大于用户出身的月份表示已过生日
                if (Integer.parseInt(yue) <= Integer.parseInt(fyue)) {
                    age = Integer.parseInt(fyear) - Integer.parseInt(year) + 1;
                    // 当前用户还没过生日
                } else {
                    age = Integer.parseInt(fyear) - Integer.parseInt(year);
                }
            }
        }
        return age;
    }

    /**
     * 获取出生日期  yyyy-MM-dd
     *
     * @param IDCard 身份证号
     * @return yyyy-MM-dd
     */
    public static String getBirthday(String IDCard) {
        String birthday = "";
        String year = "";
        String month = "";
        String day = "";
        if (StringUtils.isNotBlank(IDCard)) {
            //15位身份证号
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                // 身份证上的年份(15位身份证为1980年前的)
                year = "19" + IDCard.substring(6, 8);
                //身份证上的月份
                month = IDCard.substring(8, 10);
                //身份证上的日期
                day = IDCard.substring(10, 12);
                //18位身份证号
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                // 身份证上的年份
                year = IDCard.substring(6).substring(0, 4);
                // 身份证上的月份
                month = IDCard.substring(10).substring(0, 2);
                //身份证上的日期
                day = IDCard.substring(12).substring(0, 2);
            }
            birthday = year + "-" + month + "-" + day;
        }
        return birthday;
    }

    /**
     * 获取出生日期  yyyy-MM-dd
     *
     * @param IDCard 身份证号
     * @return yyyy-MM-dd
     */
    public static Date getBirthdayDate(String IDCard) {
        return DateKit.str2Date(getBirthday(IDCard), DateKit.FORMAT_DATE);
    }

}
